package com.seleniti.enpareja.controller.ui.view;

import java.util.Collection;

import org.ioc.commons.flowcontrol.actioncontroller.ActionController;
import org.ioc.commons.flowcontrol.common.Callback;
import org.ioc.commons.flowcontrol.common.impl.ReceiverAdapter;
import org.ioc.commons.flowcontrol.eventbus.EventBus;
import org.ioc.commons.flowcontrol.logincontroller.IsLoggedUserInfoConsumer;
import org.ioc.commons.flowcontrol.operationmanager.IsOperation;
import org.ioc.commons.flowcontrol.operationmanager.OperationManager;
import org.ioc.commons.flowcontrol.operationmanager.OperationManagerTrigger;
import org.ioc.commons.flowcontrol.operationmanager.impl.OperationHandlerFactory;
import org.ioc.commons.integration.common.RequestManager;
import org.ioc.commons.model.dataprovider.PagedDataProvider;
import org.ioc.commons.model.globaldata.GlobalDataController.Consumer;
import org.ioc.commons.model.globaldata.IsGlobalDataConsumer;
import org.ioc.commons.ui.features.HasInfoType.InfoType;
import org.ioc.commons.utils.Format;
import org.ioc.commons.utils.FormatterLogger;

import com.seleniti.enpareja.controller.common.GlobalData;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.common.domain.Page;
import com.seleniti.enpareja.controller.model.integration.database.domain.CoupleRequest;
import com.seleniti.enpareja.controller.model.integration.database.domain.CoupleType;
import com.seleniti.enpareja.controller.model.integration.database.domain.User;
import com.seleniti.enpareja.controller.model.integration.service.CoupleService;
import com.seleniti.enpareja.controller.ui.base.EnParejaViewBasePresenter;
import com.seleniti.enpareja.controller.ui.view.CoupleRequestsView.Action;
import com.seleniti.enpareja.controller.ui.view.CoupleRequestsView.Event;
import com.seleniti.enpareja.controller.ui.view.CoupleRequestsView.Operation;

/**
 * Presenter for the SignUp view
 * 
 * @author Jesús Lunar Pérez
 * 
 */
public class CoupleRequestsViewPresenter
		extends
		EnParejaViewBasePresenter<CoupleRequestsView, CoupleRequestsView.Event, CoupleRequestsView.Operation, CoupleRequestsView.Action>
		implements CoupleRequestsView.Presenter, IsLoggedUserInfoConsumer<LoggedUserInfo>,
		IsGlobalDataConsumer<GlobalData> {

	private static final FormatterLogger logger = FormatterLogger.getLogger(CoupleRequestsViewPresenter.class);

	private CoupleService coupleService;
	private PagedDataProvider<User> pageDataProvider;

	private Consumer<GlobalData> consumer;

	public CoupleRequestsViewPresenter(CoupleRequestsView display, EventBus<Event> eventbus,
			OperationManager<Operation> operationManager, ActionController<Action> actionController) {
		super(display, eventbus, operationManager, actionController);
		this.consumer = this.globalDataController.registerGlobalDataConsumer(this);
		this.consumer.requires(GlobalData.UserAgent);
	}

	@Override
	public void onInitDisplay() {
		super.onInitDisplay();
		this.coupleService = serviceManager.serviceFactory().coupleService();
		logger.info("onInitDisplay");

		this.pageDataProvider = new PagedDataProvider<User>() {

			private long totalCount;

			@Override
			public long getTotalCount() {
				return this.totalCount;
			}

			@Override
			public long getMinIndexVisibleRange() {
				return 0;
			}

			@Override
			public int getMinFecthLength() {
				return 20;
			}

			@Override
			public <O extends Enum<? extends O> & IsOperation> void fetchData(
					final Callback<Collection<User>, Throwable> callback, long start, long length, O operation,
					OperationManagerTrigger<O> trigger, String... requiredProperties) {
				String filterText = display.searchBox().getValue();
				RequestManager<Page<User>> rm;
				if (filterText == null || filterText.isEmpty()) {
					rm = serviceManager.serviceFactory().userService().getAllUsersPage(start, length, true)
							.with("elements.couple", "elements.requestsToYou.from");
				} else {
					rm = serviceManager.serviceFactory().userService()
							.getUsersPageByEmail(filterText, start, length, true)
							.with("elements.couple", "elements.requestsToYou.from");
				}

				rm.performing(Operation.GettingUsers, operationManager).caller(CoupleRequestsViewPresenter.this)
						.to(new ReceiverAdapter<Page<User>>() {

							@Override
							public void success(Page<User> result) {
								totalCount = result.getTotal();
								callback.onSuccess(result.getElements());
							}

							@Override
							public void failure(Throwable failure) {
								callback.onFailure(failure);
							}
						});

			}
		};
		display.setPagedDataProvider(pageDataProvider);

		this.loginController.requiresLoggedUserInfoIfDisplayActive(this);

		logger.exiting("onInitDisplay");
	}

	@Override
	public void onActive() {
		super.onActive();

		logger.info("Activating Get Couple view");

		shell.nonAssociatedPanelVisibility().setVisible(false);
		shell.firstStepsVisibility().setVisible(false);
		shell.nonAssociatedButtonVisibility().setVisible(!shell.firstStepsVisibility().isVisible());

		shell.refreshButtonVisibility().setVisible(true);

		refreshData();

		this.consumer.ensureRequirements();
	}

	@Override
	public void onRequiredGlobalDataReady() {
		showGoBackButtonIfRequired();
	}

	@Override
	public void onRequiredGlobalDataNotReadyYet() {
		/*
		 * Nothing to do
		 */
	}

	@Override
	public void onRequiredGlobalDataUpdated(GlobalData globalDataUpdated) {
		showGoBackButtonIfRequired();
	}

	@Override
	public void onDeactive() {
		super.onDeactive();

		logger.info("Deactivating Get Couple view");
	}

	@Override
	protected void refreshData() {
		super.refreshData();
		display.startSearch();

		this.loginController.refreshLoggedUserInfo();
	}

	protected void bindComponents() {
		super.bindComponents();
		// shell.actionController().bindAction(AppShell.Action.RefreshNow, new
		// ActionHandler<AppShell.Action>() {
		//
		// @Override
		// public void handleAction(Object sender,
		// com.seleniti.enpareja.controller.ui.main.AppShell.Action action,
		// Object... params) {
		// display.startSearch();
		// }
		// });

		operationManager.bindOperationsRunning(OperationHandlerFactory.<Operation> forLoaders(display));
		operationManager.bindOperationsRunning(OperationHandlerFactory.<Operation> forLoaders(shell.globalLoader()));

	}

	@Override
	public void onMakeCoupleRequest() {
		User selected = display.getSelectedUser();
		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();

		String requestTo = selected.getUserId();
		String requestFrom = lui.getUserId();

		logger.info("Making couple request from {0} to {1}", requestFrom, requestTo);

		serviceManager.serviceFactory().coupleService().makeCoupleRequest(requestTo, requestFrom)
				.performing(Operation.MakingRequest, operationManager).caller(this)
				.to(new ReceiverAdapter<CoupleRequest>() {

					@Override
					public void success(CoupleRequest result) {
						logger.info("Couple request made {0}. Refreshing logged user info...", result);

						display.clearSelection();

						refreshData();

						shell.nonAssociatedPanelVisibility().setVisible(false);
						shell.firstStepsVisibility().setVisible(false);
						shell.nonAssociatedButtonVisibility().setVisible(!shell.firstStepsVisibility().isVisible());
						display.ableToGetCoupleInfo().setVisible(false);
						display.makeCoupleRequestActionVisibility().setVisible(false);
						display.requestSentInfo().setVisible(true);
					}
				});
	}

	@Override
	public void onSelectedUserChanged() {
		refreshActionsFromSelected();
	}

	protected void refreshActionsFromSelected() {
		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();

		User selected = display.getSelectedUser();

		logger.info("Refreshing actions from selected: {0} Logged user info: {1}", selected, lui);

		boolean makeCoupleRequestAction = lui != null
				&& (lui.getCoupleId() == null || lui.getCoupleType() != CoupleType.USERS_COUPLE) && selected != null
				&& (selected.getCouple() == null || selected.getCoupleType() != CoupleType.USERS_COUPLE);
		boolean unableToGetCoupleInfo = lui != null && (lui.getCoupleId() == null || lui.getCoupleType() != CoupleType.USERS_COUPLE) && selected != null
				&& selected.getCouple() != null && selected.getCoupleType() == CoupleType.USERS_COUPLE;

		boolean requestAlreadyMade = false;

		if (makeCoupleRequestAction && selected != null && selected.getRequestsToYou() != null
				&& !selected.getRequestsToYou().isEmpty()) {
			for (CoupleRequest cr : selected.getRequestsToYou()) {
				if (lui.getUserId().equals(cr.getFrom().getUserId())) {
					makeCoupleRequestAction = false;
					requestAlreadyMade = true;
					break;
				}
			}
		}

		display.ableToGetCoupleInfo().setVisible(makeCoupleRequestAction);
		display.makeCoupleRequestActionVisibility().setVisible(makeCoupleRequestAction);
		display.requestAlreadyMadeInfo().setVisible(requestAlreadyMade);
		display.unableToGetCoupleInfo().setVisible(unableToGetCoupleInfo);

		if (makeCoupleRequestAction || unableToGetCoupleInfo || requestAlreadyMade) {
			display.requestSentInfo().setVisible(false);
		}

		boolean coupleGotInfo = lui != null && lui.getCoupleId() != null && !makeCoupleRequestAction
				&& !requestAlreadyMade && !unableToGetCoupleInfo && !display.requestSentInfo().isVisible();
		display.coupleGotInfo().setVisible(coupleGotInfo);

		if (lui != null && lui.getCoupleType() == CoupleType.SINGLE_USER) {
			display.coupleGotInfo().setType(InfoType.INFO);
			display.coupleGotInfo().setText(
					Format.substitute("Actualmente estás utilizando la aplicación en modo soltero."));
		} else if (lui != null && lui.getCoupleType() == CoupleType.TESTING_MODE_COUPLE) {
			display.coupleGotInfo().setType(InfoType.INFO);
			display.coupleGotInfo().setText(
					Format.substitute("Actualmente estás utilizando la aplicación en modo de prueba."));
		} else {
			display.coupleGotInfo().setType(InfoType.OPERATION_OK);
			display.coupleGotInfo().setText(
					Format.substitute("Enhorabuena. Ya estás emparejado{0} ☺.",
							lui != null && lui.getCoupleName() != null && !lui.getCoupleName().isEmpty() ? " con "
									+ lui.getCoupleName() : ""));
		}


	}

	@Override
	public void onLoggedUserInfoNotReadyYet() {
		/*
		 * Nothing to do
		 */
	}

	@Override
	public void onLoggedUserInfoDataReady() {
		if (display.isActive()) {
			logger.info("Global data ready");
			refreshActionsFromSelected();
		}
	}

	@Override
	public void onLoggedUserInfoDataUpdated(LoggedUserInfo loggedUserInfo) {
		if (display.isActive()) {
			refreshActionsFromSelected();
		}
	}

	@Override
	public void onDismissSelectedRequest() {
		User selected = display.getSelectedUser();
		LoggedUserInfo lui = this.loginController.getLoggedUserInfo();
		if (selected != null && lui != null && lui.getUserId() != null) {
			display.clearSelection();
			refreshActionsFromSelected();

			this.coupleService.dismissCoupleRequest(lui.getUserId(), selected.getUserId()).caller(this)
					.performing(Operation.DismissingCoupleRequest, operationManager).to(new ReceiverAdapter<Void>() {

						@Override
						public void success(Void result) {
							refreshData();
							loginController.refreshLoggedUserInfo();
						}
					});
		}
	}
}
